package com.randi.framework.security.service;

import java.util.concurrent.TimeUnit;

import com.randi.common.config.AppConfig;
import com.randi.common.constant.CacheConstants;
import com.randi.common.utils.RedisUtil;
import com.randi.framework.security.context.AuthenticationContextHolder;
import com.randi.common.utils.SecurityUtils;
import com.randi.common.core.domain.entity.SysUser;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;


import javax.annotation.Resource;

/**
 * @author ziye
 */
@Component
public class PasswordService {

    /**
     * 密码最大错误次数
     */
    private int maxRetryCount;
    /**
     * 密码锁定时间，单位：分钟
     */
    private int lockTime;
    /**
     * 密码更新最大错误次数
     */
    private int updateMaxRetryCount;
    /**
     * 密码更新锁定时间，单位：分钟
     */
    private int updateLockTime;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private void init(AppConfig.SystemConfig.PasswordConfig passwordConfig) {
        maxRetryCount = passwordConfig.getMaxRetryCount();
        lockTime = passwordConfig.getLockTime();
        updateMaxRetryCount = passwordConfig.getUpdateMaxRetryCount();
        updateLockTime = passwordConfig.getUpdateLockTime();
    }

    /**
     * 登录账户密码错误次数缓存键名
     *
     * @param username 用户名
     * @return 缓存键key
     */
    private String getCacheKey(String username) {
        return CacheConstants.PWD_ERR_CNT_KEY + username;
    }

    /**
     * 校验密码
     *
     * @param user        用户
     * @param rawPassword 密码
     * @return boolean
     */
    public boolean matches(SysUser user, String rawPassword) {
        return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
    }

    /**
     * 清除
     *
     * @param loginName loginName
     */
    public void clearLoginRecordCache(String loginName) {
        if (redisUtil.hasKey(getCacheKey(loginName))) {
            redisUtil.delete(getCacheKey(loginName));
        }
    }

    /**
     * 是否锁定
     *
     * @param username 用户名
     * @return true/false
     */
    public boolean isLocking(String username) {
        Integer retryCount = redisUtil.getCache(getCacheKey(username));
        if (retryCount == null) {
            retryCount = 0;
        }
        return retryCount >= maxRetryCount;
    }

    /**
     * 获取锁定剩余时间
     *
     * @param username 用户名
     * @return true/false
     */
    public Integer getLockingTime(String username) {
        Long expire = redisUtil.getExpire(getCacheKey(username));
        if (expire < 0L) {
            return 0;
        }
        return (int) Math.ceil(expire / 60.0D);
    }

    /**
     * 获取可重复次数
     *
     * @param userName 用户名
     * @return true/false
     */
    public Integer getRetryCount(String userName) {
        Integer retryCount = redisUtil.getCache(getCacheKey(userName));
        if (retryCount == null) {
            retryCount = 0;
        }
        return retryCount;
    }

    /**
     * 校验密码
     *
     * @param user 用户
     * @return true/false
     */
    public boolean validatePassword(SysUser user) {
        Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
        String username = usernamePasswordAuthenticationToken.getName();
        String password = usernamePasswordAuthenticationToken.getCredentials().toString();
        Integer retryCount = getRetryCount(username);
        if (!matches(user, password)) {
            retryCount = retryCount + 1;
            redisUtil.setCache(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
            return false;
        }
        this.clearLoginRecordCache(username);
        return true;
    }

    /**
     * 修改账户密码错误次数缓存键名
     *
     * @param userId 用户ID
     * @return 缓存键key
     */
    private String getUpdateCacheKey(Long userId) {
        return CacheConstants.PWD_EDIT_ERR_CNT_KEY + userId;
    }

    /**
     * 更新是否锁定
     *
     * @return true/false
     */
    public boolean isUpdateLocking() {
        Long userId = SecurityUtils.getUserId();
        Integer retryCount = redisUtil.getCache(getUpdateCacheKey(userId));
        if (retryCount == null) {
            retryCount = 0;
        }
        return retryCount >= updateMaxRetryCount;
    }

    /**
     * 获取更新可重复次数
     *
     * @return true/false
     */
    public Integer getUploadRetryCount() {
        Long userId = SecurityUtils.getUserId();
        Integer retryCount = redisUtil.getCache(getUpdateCacheKey(userId));
        if (retryCount == null) {
            retryCount = 0;
        }
        return retryCount;
    }

    /**
     * 更新校验密码
     *
     * @param currentPassword 新密码
     * @param user            SysUser
     * @return true/false
     */
    public boolean updateValidatePassword(String currentPassword, SysUser user) {
        String updateCacheKey = getUpdateCacheKey(user.getUserId());
        if (!SecurityUtils.matchesPassword(currentPassword, user.getPassword())) {
            Integer retryCount = getUploadRetryCount();
            retryCount = retryCount + 1;
            redisUtil.setCache(updateCacheKey, retryCount, updateLockTime, TimeUnit.MINUTES);
            return false;
        }
        // 清除缓存
        if (redisUtil.hasKey(updateCacheKey)) {
            redisUtil.delete(updateCacheKey);
        }
        return true;
    }

}
